package com.qingjiang.projectschedule.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingjiang.projectschedule.mapper.ProjectInformationMapper;
import com.qingjiang.projectschedule.mapper.ProjectScheduleMapper;
import com.qingjiang.projectschedule.pojo.NodeOperation;
import com.qingjiang.projectschedule.pojo.ProjectAllInformation;
import com.qingjiang.projectschedule.pojo.ProjectInformation;
import com.qingjiang.projectschedule.pojo.ProjectSchedule;
import com.qingjiang.projectschedule.service.ConfigService;
import com.qingjiang.projectschedule.service.DepartmentService;
import com.qingjiang.projectschedule.service.ProjectNodeService;
import com.qingjiang.projectschedule.service.ProjectScheduleService;
import com.qingjiang.projectschedule.utils.DateUtil;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author jx
 * @description 针对表【project_schedule(项目进度表)】的数据库操作Service实现
 * @createDate 2024-03-13 20:05:11
 */
@Service
public class ProjectScheduleServiceImpl extends ServiceImpl<ProjectScheduleMapper, ProjectSchedule>
        implements ProjectScheduleService {
    @Autowired
    private ProjectScheduleMapper projectScheduleMapper;

    @Autowired
    private ProjectInformationMapper projectInformationMapper;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private ProjectNodeService nodeService;

    @Autowired
    private ConfigService configService;

    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    private static SimpleDateFormat importExcelFormat = new SimpleDateFormat("yyyy.MM.dd");

    @Override
    public boolean addOne(ProjectAllInformation projectAllInformation) {
        projectAllInformation.setNodeMap();
        Map<Integer, String[]> nodeMap = projectAllInformation.getNodeMap();
        int rows = 0;
        for (int i = 1; i < 8; i++) {
            ProjectSchedule projectSchedule = new ProjectSchedule();
            projectSchedule.setProjectId(projectAllInformation.getProjectId());
            projectSchedule.setNodeId(i);
            try {
                projectSchedule.setScheduleStartTime(dateFormat.parse(nodeMap.get(i)[0]));
                projectSchedule.setScheduleEndTime(dateFormat.parse(nodeMap.get(i)[1]));
                projectSchedule.setDelayTotime(dateFormat.parse(nodeMap.get(i)[1]));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            if (i == 1) projectSchedule.setNodeState(1);
            else projectSchedule.setNodeState(0);
            rows += projectScheduleMapper.insert(projectSchedule);
        }
        return rows == 7;
    }

    @Override
    public boolean updateProject(ProjectAllInformation projectAllInformation) {
        projectAllInformation.setNodeMap();
        Map<Integer, String[]> nodeMap = projectAllInformation.getNodeMap();
        int rows = 0;
        for (int i = 1; i < 8; i++) {
            if ("".equals(nodeMap.get(i)[0]) || "".equals(nodeMap.get(i)[1])) {
                rows += 1;
                continue;
            }
            LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
            try {
                updateWrapper.eq(ProjectSchedule::getProjectId, projectAllInformation.getProjectId())
                        .eq(ProjectSchedule::getNodeId, i)
                        .set(ProjectSchedule::getScheduleStartTime, dateFormat.parse(nodeMap.get(i)[0]))
                        .set(ProjectSchedule::getScheduleEndTime, dateFormat.parse(nodeMap.get(i)[1]))
                        .set(ProjectSchedule::getDelayTotime, dateFormat.parse(nodeMap.get(i)[1]));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            rows += projectScheduleMapper.update(null, updateWrapper);
        }
        return rows == 7;
    }

    @Override
    public boolean reportProject(ProjectAllInformation projectAllInformation) {
        System.out.println("reportProject");
        System.out.println(projectAllInformation);
        projectAllInformation.setNodeMap();
        Map<Integer, String[]> nodeMap = projectAllInformation.getNodeMap();
        int rows = 0;
        int curNode = 1;
        for (int i = 1; i <= 7; i++) {
            if (nodeMap.get(i)[0].equals("")) {
//                curNode = i;
//                break;
                continue;
            }
            curNode = i;
            ProjectSchedule projectSchedule = getNodeEndTime(projectAllInformation.getProjectId(), i);
            Integer nodeState = 0;

            LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
            try {
                nodeState = CalNodeStatus(projectSchedule.getScheduleEndTime(), dateFormat.parse(nodeMap.get(i)[1]));
//                System.out.println("节点:" + i + " " + nodeState);
                updateWrapper.eq(ProjectSchedule::getProjectId, projectAllInformation.getProjectId())
                        .eq(ProjectSchedule::getNodeId, i)
                        .set(ProjectSchedule::getActualStartTime, dateFormat.parse(nodeMap.get(i)[0]))
                        .set(ProjectSchedule::getActualEndTime, dateFormat.parse(nodeMap.get(i)[1]))
                        .set(ProjectSchedule::getNodeState, nodeState)
                        .set(ProjectSchedule::getDelayReason, projectAllInformation.getDelayReason()[i]);

                rows += projectScheduleMapper.update(null, updateWrapper);


//                projectScheduleMapper.update(null, updateState);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        }
//        if (curNode < 7)
//            curNode++;
        int nextNodeId = curNode + 1;
        //判断当前节点是否为空
        while (nextNodeId <= 7) {
            ProjectSchedule projectSchedule = getCurNode(projectAllInformation.getProjectId(), nextNodeId);
            if (projectSchedule.getScheduleStartTime() != null && !projectSchedule.getScheduleStartTime().equals("")) {
                break;
            }
            nextNodeId++;
        }
        if (nextNodeId > 7) {
            nextNodeId = 7;
        }
        LambdaUpdateWrapper<ProjectInformation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectInformation::getProjectId, projectAllInformation.getProjectId())
                .set(ProjectInformation::getCurrentNodeid, nextNodeId);
        Integer rows2 = projectInformationMapper.update(null, updateWrapper);
//        System.out.println("rows" + rows + " rows2" + rows2);
        return rows2 == 1;
    }

    @Override
    @Transactional
    public int uploadExcel(Row row, String projectId, int curNode) {
        int num = 0;
        int index = 5;
        for (int j = 1; j <= 7; j++) {
            ProjectSchedule projectSchedule = new ProjectSchedule();
            projectSchedule.setProjectId(projectId);
            projectSchedule.setNodeId(j);
            Cell cellBegin = row.getCell(index);
            Cell cellEnd = row.getCell(index + 1);
            if (cellBegin != null && cellEnd != null) {
                if (cellBegin.getCellType() != CellType.STRING && cellEnd.getCellType() != CellType.STRING && HSSFDateUtil.isCellDateFormatted(cellBegin) && HSSFDateUtil.isCellDateFormatted(cellEnd)) {
                    /*Date begin = HSSFDateUtil.getJavaDate(cellBegin.getNumericCellValue());
                    Date end = HSSFDateUtil.getJavaDate(cellEnd.getNumericCellValue());*/
                    Date begin = cellBegin.getDateCellValue();
                    Date end = cellEnd.getDateCellValue();
                    if (begin != null && end != null) {
                        projectSchedule.setScheduleStartTime(begin);
                        projectSchedule.setScheduleEndTime(end);
                        projectSchedule.setDelayTotime(end);
                    } else {
                        projectSchedule.setScheduleStartTime(null);
                        projectSchedule.setScheduleEndTime(null);
                        projectSchedule.setDelayTotime(null);
                    }
                }
            }
            if (j <= curNode) projectSchedule.setNodeState(1);
            else projectSchedule.setNodeState(0);
            num += projectScheduleMapper.insert(projectSchedule);
            index += 2;
        }
        return num;
    }


    @Override
    public int checkScheduleTime(Row row) {
        int index = 5;
        int curNode = 7;
        for (int i = 1; i <= 7; i++) {
            Cell cellBegin = row.getCell(index);
            Cell cellEnd = row.getCell(index + 1);
            if (cellBegin != null && cellEnd != null) {
                if (cellBegin.getCellType() != CellType.STRING && cellEnd.getCellType() != CellType.STRING && HSSFDateUtil.isCellDateFormatted(cellBegin) && HSSFDateUtil.isCellDateFormatted(cellEnd)) {
                    /*Date begin = HSSFDateUtil.getJavaDate(cellBegin.getNumericCellValue());
                    Date end = HSSFDateUtil.getJavaDate(cellEnd.getNumericCellValue());*/
                    Date begin = cellBegin.getDateCellValue();
                    Date end = cellEnd.getDateCellValue();
                    if (begin == null && end == null) {
                        index += 2;
                        continue;
                    }
                    curNode = Math.min(curNode, i);
                    if (!begin.before(end)) return -1;
                }
            }
            index += 2;
        }
        return curNode;
    }

    @Override
    public List<ProjectSchedule> queryProject(String projectId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(projectId != null, ProjectSchedule::getProjectId, projectId);
        queryWrapper.orderByAsc(ProjectSchedule::getNodeId);
        return projectScheduleMapper.selectList(queryWrapper);
    }

    @Override
    public String nodeFinish(NodeOperation nodeOperation) {
        LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
        Date actualEndTime = null, actualStartTime = null;
        try {
            if (nodeOperation.getStartTime() != null && !nodeOperation.getStartTime().isEmpty()) {
                actualStartTime = dateFormat.parse(nodeOperation.getStartTime());
            }
            if (nodeOperation.getEndTime() != null && !nodeOperation.getEndTime().isEmpty()) {
                actualEndTime = dateFormat.parse(nodeOperation.getEndTime());
            }
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        //根据完成时间更新节点状态
        LambdaQueryWrapper<ProjectSchedule> scheduleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        scheduleLambdaQueryWrapper.eq(ProjectSchedule::getProjectId, nodeOperation.getProjectId())
                .eq(ProjectSchedule::getNodeId, nodeOperation.getNodeId());

        ProjectSchedule projectSchedule = projectScheduleMapper.selectOne(scheduleLambdaQueryWrapper);
        Date planEndTime = projectSchedule.getScheduleEndTime();
        int originState = projectSchedule.getNodeState();
        long dayDiff = actualEndTime != null ? DateUtil.calDayDiff(planEndTime, actualEndTime) : 0;
        int nodeState = 1;

        int WARNING = configService.getYellowDays();
        if (dayDiff > 0) {
            if (dayDiff <= WARNING) {
                nodeState = 2;
            } else {
                nodeState = 3;
            }
        }

        updateWrapper.eq(ProjectSchedule::getProjectId, nodeOperation.getProjectId())
                .eq(ProjectSchedule::getNodeId, nodeOperation.getNodeId())
                .set(ProjectSchedule::getActualStartTime, actualStartTime);
        if (nodeOperation.getEndTime() != null && !nodeOperation.getEndTime().isEmpty()) {
            updateWrapper.set(ProjectSchedule::getActualEndTime, actualEndTime)
                    .set(ProjectSchedule::getNodeState, nodeState);
        }

        if (nodeOperation.getDelayReason() != null) {
            updateWrapper.set(ProjectSchedule::getDelayReason, nodeOperation.getDelayReason());
        }

        Integer rows = projectScheduleMapper.update(null, updateWrapper);
        if (rows == 1) {
            System.out.println("更新节点实际时间成功");
            return "ok";
        }
        return "节点实际结束时间设置失败";
    }

    @Override
    public int CalNodeStatus(Date planEndTime, Date actualEndTime) {
        long dayDiff = DateUtil.calDayDiff(planEndTime, actualEndTime);
        int nodeState = 1;
        int WARNING = configService.getYellowDays();
        if (dayDiff > 0) {
            if (dayDiff <= WARNING) {
                nodeState = 2;
            } else {
                nodeState = 3;
            }
        }
        return nodeState;
    }

    @Override
    public String getDelayReason(String projectId, Integer nodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(ProjectSchedule::getDelayReason).eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId);
        List<Object> delayReasons = projectScheduleMapper.selectObjs(queryWrapper);
        return (String) delayReasons.get(0);
    }

    @Override
    public List<Map<String, Object>> getNodesByCond(String projectId, int lastNode, int curNodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(ProjectSchedule::getNodeId, ProjectSchedule::getNodeState)
                .eq(ProjectSchedule::getProjectId, projectId)
                .ge(ProjectSchedule::getNodeId, lastNode)
                .le(ProjectSchedule::getNodeId, curNodeId);
        List<Map<String, Object>> maps = projectScheduleMapper.selectMaps(queryWrapper);
        return maps;
    }

    @Override
    public ProjectSchedule selectByProjectIdAndNodeId(String projectId, String nodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId);
        return projectScheduleMapper.selectOne(queryWrapper);
    }

    @Override
    public void updateByProjectIdAndNodeId(ProjectSchedule projectSchedule) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectSchedule::getProjectId,projectSchedule.getProjectId())
                        .eq(ProjectSchedule::getNodeId, projectSchedule.getNodeId());
        projectScheduleMapper.update(projectSchedule,queryWrapper);
    }

    @Override
    public boolean setDelayReason(NodeOperation operation) {
        LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectSchedule::getProjectId, operation.getProjectId())
                .eq(ProjectSchedule::getNodeId, operation.getNodeId())
                .set(ProjectSchedule::getDelayReason, operation.getDelayReason());
        Integer rows = projectScheduleMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public void updateDelayToTimeById(String projectId, Integer nodeId, Date delayTotime) {
        LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectSchedule::getProjectId, projectId).eq(ProjectSchedule::getNodeId, nodeId)
                .set(ProjectSchedule::getDelayTotime, dateFormat.format(delayTotime));
        projectScheduleMapper.update(null, updateWrapper);
    }

    @Override
    public ProjectSchedule getNodeEndTime(String projectId, Integer nodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId);
        return projectScheduleMapper.selectOne(queryWrapper);
    }

    @Override
    public Date getNodeActualEndTime(String projectId, Integer nodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId);
        return projectScheduleMapper.selectOne(queryWrapper).getActualEndTime();
    }

    @Override
    public List<Map<String, Object>> getNodeByColor(String projectId, String projectName, String color) {
        LambdaQueryWrapper<ProjectSchedule> scheduleQueryWrapper = new LambdaQueryWrapper<>();
        scheduleQueryWrapper.select(ProjectSchedule::getNodeId);
        if ("yellow".equals(color)) {
            scheduleQueryWrapper.eq(ProjectSchedule::getNodeState, 2);
        } else {
            scheduleQueryWrapper.eq(ProjectSchedule::getNodeState, 3);
        }
        scheduleQueryWrapper.eq(ProjectSchedule::getProjectId, projectId);
        List<Map<String, Object>> maps = projectScheduleMapper.selectMaps(scheduleQueryWrapper);
        for (Map<String, Object> map : maps) {
            Integer nodeId = (Integer) map.get("node_id");
            String nodeName = nodeService.getNodeNameById(nodeId);
            String delayReason = getDelayReason(projectId, nodeId);
            map.put("project_id", nodeId);
            //在统计页面，点击按钮查看滞后项目，只显示第一个项目名称
            map.put("project_name", "");
            map.put("node_name", map.get("node_id") + "-" + nodeName);
            map.put("delay_reason", delayReason);
        }
        return maps;
    }

    @Override
    public List<Map<String, Object>> getNodeByNodeIds(String projectId, String nodes) {
        String[] nodeIds = nodes.split(",");
        LambdaQueryWrapper<ProjectSchedule> scheduleQueryWrapper = new LambdaQueryWrapper<>();
        scheduleQueryWrapper.select(ProjectSchedule::getNodeId, ProjectSchedule::getDelayReason).eq(ProjectSchedule::getProjectId,
                        projectId)
                .in(ProjectSchedule::getNodeId, nodeIds);
        List<Map<String, Object>> maps = projectScheduleMapper.selectMaps(scheduleQueryWrapper);
        for (Map<String, Object> map : maps) {
            if (!map.containsKey("delay_reason")){
               map.put("delay_reason", "");
            }
            Integer nodeId = (Integer) map.get("node_id");
            String nodeName = nodeService.getNodeNameById(nodeId);
            map.put("project_id", nodeId);
            //在统计页面，点击按钮查看滞后项目，只显示第一个项目名称
            map.put("project_name", "");
            map.put("node_name", map.get("node_id") + "-" + nodeName);
        }
        return maps;
    }

    public boolean setNodeState(String projectId, Integer nodeId, Integer nodeState) {
        LambdaUpdateWrapper<ProjectSchedule> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId)
                .set(ProjectSchedule::getNodeState, nodeState);
        Integer rows = projectScheduleMapper.update(null, updateWrapper);
        return rows == 1;
    }

    @Override
    public ProjectSchedule getCurNode(String projectId, Integer nodeId) {
        LambdaQueryWrapper<ProjectSchedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectSchedule::getProjectId, projectId)
                .eq(ProjectSchedule::getNodeId, nodeId);
        ProjectSchedule projectSchedule = projectScheduleMapper.selectOne(queryWrapper);
        return projectSchedule;
    }

}




